from storehouse.models import inventory
from storehouse.models import product, storehouse, person
from storehouse.models import order_product,order_state
from storehouse.models import *
from django.db import IntegrityError
import sys
from django.db.models import Q
from django.core.exceptions import ValidationError

def getPersonStorehouses(person_in):
    pass
def calculatePrice(order_product_instances):
    order_products = order_product_instances
    sum =0
    print "ORDERS:",order_products
    for order_product_it in order_products:
        product_o = product.objects.get(id = order_product_it.product.id)
        sum+= order_product_it.quantity * product_o.sell_price
    #TODO add rabats
    return sum
#this one in order_product saver
def sourceCapacityTest(order, order_product_instances,change):
    """
    sourceCapacityTest(order, order_product_instances,change)
    checks if order can be completed
        if there is enough products to send
    Arguments:
        order - order
        order_product_instances -  instances of order_product connected with order
        change - not used
    Returns:
        True
    Throws:
        ValidationError
    """

    #if not(order.state in order_state.objects.filter(name__in = ['Oczekujacy na PW','Oczekujacy na PZ'])):
     #   return True
    try:
        storehouse_o = order.storehouse_from
    except:
        return True
    if not storehouse_o:
        return True
    for order_product_i in order_product_instances:
        try:
            product_q  = product.objects.get(id = order_product_i.product.id)
            palete_type_q =order_product_i.palette_type
            storehouse_products_o = storehouse_product.objects.filter(storehouse=storehouse_o,
                                                                  product = product_q,
                                                                  palete_type = palete_type_q
                                                                  )
            products_in_storehouse_count  =0 
            for storehouse_product_o in storehouse_products_o:
                products_in_storehouse_count+=1
        except:
            raise ValidationError("No product %s(palette %s) in storehouse %s \n%s" %(product_q,palete_type_q,storehouse_o,sys.exc_info()))
        
        booked_out = None
        try:
            booked_out = storehouse_product_book_out.objects.filter(storehouse=storehouse_o,
                                                                  product = product.objects.get(id = order_product_i.product),
                                                                  palete_type = order_product_i,
                                                                  ).exclude(order=order)
        except:
            pass
        booked_out_quantity = 0
        try:
            booked_out_quantity += sum([booked_q.quantity for booked_q in booked_out])
        except:
            pass
        print "S Productsss:",products_in_storehouse_count
        print "ORDER:",order_product_i.quantity
        if products_in_storehouse_count  - booked_out_quantity < order_product_i.quantity:
            raise ValidationError("Not enough product %s (palette %s) in storehouse %s \n%s" %(product_q,palete_type_q,storehouse_o,sys.exc_info()))
    return True
    
def destinationCapacityTest(order, order_product_instances,change):
    """
    destinationCapacityTest(order, order_product_instances,change)
    check if order can be completed
        if is enough space in destinatoin storehouse
    Arguments:
        order - order
        order_product_instances -  instances of order_product connected with order
        change - not used
    Returns:
        True
    Throws:
        ValidationError

    """
    to_person = order.partner_to 
    try:
        storehouse_o = order.storehouse_to
    except:
        return True
    if not storehouse_o:
        return True
    product_paletes_count = {}
    product_order_count = {}
    storehouse_volumes_count = {}
    storehouse_booked_in_count = {}
    palette_types = palette_type.objects.all()
    print "palette counters"
    # init palette counters
    for palette_type_i in palette_types:
        product_paletes_count[palette_type_i]=0
        product_order_count[palette_type_i]  =0
        storehouse_volumes_count[palette_type_i] =0
        storehouse_booked_in_count [palette_type_i] = 0
    #COUNT palettes in order
    #chec type
    print "order counters"
    storehouse_product_categories = storehouse.objects.get(id = storehouse_o.id).product_categories.all()
    for order_product_i in order_product_instances:
        product_order_count[order_product_i.palette_type]+=order_product_i.quantity
        if not (order_product_i.product.category in storehouse_product_categories):
            raise ValidationError("This storehouse cannot store %s !" % order_product_i.product.category.name)
    #COUNT palettes in storehouse
    print "palettes"
    storehouse_products = storehouse_product.objects.filter(storehouse = storehouse_o)
    print "get S products"
    for storehouse_product_i in storehouse_products:
        product_paletes_count[storehouse_product_i.palete_type]+= 1
    #GET storehouse volume
    print "volume counters"
    storehouse_volumes = storehouse_volume.objects.filter(storehouse = storehouse_o) 
    for storehouse_volume_i in storehouse_volumes:
        storehouse_volumes_count[storehouse_volume_i.palete_type] += storehouse_volume_i.quantity
    #GET booked in
    storehouse_booked_in = storehouse_product_book_in.objects.filter(storehouse = storehouse_o).exclude(order = order)
    for bookedIn in storehouse_booked_in:
        storehouse_booked_in_count[bookedIn.palete_type] += bookedIn.quantity 
    
    #check volume
    for palette_type_i in palette_types:
        if int(product_paletes_count[palette_type_i] or 0) +int( product_order_count[palette_type_i] or 0) \
            +int(storehouse_booked_in_count[palette_type_i] or 0) \
                >  int (storehouse_volumes_count[palette_type_i] or 0):
            raise ValidationError("not enough space in destination storehouse %s" %(storehouse_o))
        
    return True
def orderDestinationCapacityTest(order_in):
    order_product_instances = order_product.objects.filter(order = order_in)
    destinationCapacityTest(order_in, order_product_instances, change =  False)
    
def orderSourceCapacityTest(order_in):
    order_product_instances = order_product.objects.filter(order = order_in)
    sourceCapacityTest(order_in, order_product_instances, change = False)

def isPersonStorehouseManager(person_in):
    """
    isPersonStorehouseManager(person_in)
    checks if person is storehouse manager
    Argumensts:
        person_in - preson to be checked
    Returns:
        True if person is storehouse manager
        False if else
    """
    
    managers = person.objects.filter(user__in= user.objects.filter(user_ptr__in=User.objects.filter(groups__name = 'Managerowie Magazynow')))
    try:
        persons_storehouse = storehouse.objects.get(manager = person_in)
    except:
        return False
    
    if person_in in managers:
        return True
    return False
def isPersonLogisticSupervisor(person_in):
    """
    isPersonLogisticSupervisor(person_in)
    checks if person is storehouse manager
    Argumensts:
        person_in - preson to be checked
    Returns:
        True if person is logistic supervisor
        False if else
    """
    try:
        supervisors = person.objects.filter(user__in= user.objects.filter(user_ptr__in=User.objects.filter(groups__name = 'Nadzorcy Logistykow')))
    except:
            return False
    if person_in in supervisors:
        return True
    return False

def isPersonLogistic(person_in):
    """
    isPersonLogistic(person_in)
    checks if person is storehouse manager
    Argumensts:
        person_in - preson to be checked
    Returns:
        True if person is logistic
        False if else
    """
    try:
        logistic = person.objects.filter(user__in= user.objects.filter(user_ptr__in=User.objects.filter(groups__name = 'Logistycy')))
    except:
        return False
    if person_in in logistic:
        return True
    return False
def isPersonStorehouseStaff(person_in):
    """
    isPersonStorehouseStaff(person_in)
    checks if person is connected with storehose
    Arguments:
        person_in - person to be chcecked
    Returns:
        True if person is connected with storehouse
        False if else
    """
    storehouses = None
    try:
        storehouses = storehouse.objects.filter(person = person_in)
    except:
        return False
    if storehouses:
        return True
    return False

def isOrderCancelable(order_in):
    """
    isOrderCancelable(order_in)
    chcecks if order can be canceled
    Arguments:
        order_in - order to be chcecked
    Returns:
        True if order can be canceled
        False if else
    """
    try:
        if order_in.state in order_state.objects.filter(name__in = ['Oczekujacy na RW','Oczekujacy na PZ','Oczekujacy na WZ']):
            return True
    except:
        return False
    return False
def OrderCanBeArchived(order_in):
    """
    OrderCanBeArchived(order_in)
    chcecks if order can be archived
    Arguments:
        order_in - order to be chcecked
    Returns:
        True if order can be archived
        False if else
    """
    try:
        if order_in.state in order_state.objects.filter(name__in = ['Zrealizowany','Anulowany']):
            return True
    except:
        return False
    return False
def getUserStorehouses(user_in):
    """
    getUserStorehouses(user_in)
    gets storehouses connected with user
    Arguments:
        user_in - user
    Returns:
        list of user storehouses or empty list
    """
    try:
        person_o = person.objects.get(user = user.objects.get(user_ptr = user_in) )
        user_storehouses = storehouse.objects.filter(Q(person = person_o)|Q(manager = person_o)).distinct()
    except:
            return []
    return user_storehouses
def getInventoriedStorehouses():
    """
    getInventoriedStorehouses
    get all storehouses under inventory
    Arguments:
        None
    Return:
        list of inventoried storehouses or empty list
    """
    inventoriedStorehouses = []
    activeInventories  = inventory.objects.filter(is_applied = False,is_canceled=False)
    activeInventoriesDocuments = document.objects.filter(inventory__in = activeInventories)

    storehouses = []
    for activeInventoryDocument in activeInventoriesDocuments:
        storehouses.append(activeInventoryDocument.storehouse.id)
    inventoriedStorehouses = storehouse.objects.filter(id__in = storehouses).distinct()
    return inventoriedStorehouses

def hasStorehouseUnappliedInventory(storehouse_in):
    """
    hasStorehouseUnappliedInventory(storehouse_in)
    chceck if storehouse has unapplied inventory
    Arguments:
        storehouse_in - storehouse to be checked
    Returns:
        True if storehouse has unapplied inventory
        False if else
    """
    inventoriedStorehouses = getInventoriedStorehouses()
    if storehouse_in in inventoriedStorehouses:
        return True
    return False